package com.lazi.june.common.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.io.IOException;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;

/**
 * desc:
 * JSON 工具类（线程安全，基于 Jackson ObjectMapper）
 * 适用于 JDK 17，推荐使用 Jackson 2.15+
 *
 * @author huliqian
 * @since 2025/8/21
 */
public final class JsonUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        // 1. 基础配置
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        // 2. 日期格式（使用线程安全的 StdDateFormat，并统一系统默认时区）
        OBJECT_MAPPER.setDateFormat(new StdDateFormat().withTimeZone(TimeZone.getDefault()));
        OBJECT_MAPPER.setTimeZone(TimeZone.getDefault());

        // 3. Long 转 String，防止 JS 精度丢失
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        OBJECT_MAPPER.registerModule(simpleModule);

        // 4. Java 8 时间模块
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));

        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));

        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));

        OBJECT_MAPPER.registerModule(javaTimeModule);
    }

    private JsonUtil() {
        throw new UnsupportedOperationException("JsonUtil 是工具类，不可实例化");
    }

    /**
     * 注册自定义 Module（线程安全）
     */
    public static synchronized void registerModule(Module module) {
        OBJECT_MAPPER.registerModule(module);
    }

    /**
     * 获取全局 ObjectMapper（只读，避免外部修改）
     */
    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER.copy();
    }

    // ================= 序列化 =================

    public static String toJsonStr(Object object) {
        try {
            return OBJECT_MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("序列化对象失败: " + object, e);
        }
    }

    public static String toJsonPrettyStr(Object object) {
        try {
            return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("序列化对象失败: " + object, e);
        }
    }

    public static byte[] toJsonBytes(Object object) {
        try {
            return OBJECT_MAPPER.writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("序列化对象失败: " + object, e);
        }
    }

    // ================= 反序列化 =================

    public static <T> T toBean(String content, Class<T> valueType) {
        try {
            return OBJECT_MAPPER.readValue(content, valueType);
        } catch (IOException e) {
            throw new IllegalArgumentException("反序列化 JSON 失败: " + content, e);
        }
    }

    public static <T> T toBean(String content, TypeReference<T> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(content, typeReference);
        } catch (IOException e) {
            throw new IllegalArgumentException("反序列化 JSON 失败: " + content, e);
        }
    }

    public static <T> T toBean(byte[] content, Class<T> valueType) {
        try {
            return OBJECT_MAPPER.readValue(content, valueType);
        } catch (IOException e) {
            throw new IllegalArgumentException("反序列化 JSON 失败: " + Arrays.toString(content), e);
        }
    }

    public static JsonNode toNode(String content) {
        try {
            return OBJECT_MAPPER.readTree(content);
        } catch (IOException e) {
            throw new IllegalArgumentException("解析 JSON Node 失败: " + content, e);
        }
    }

    /**
     * JSON 字符串转 List
     */
    public static <T> List<T> toList(String content, Class<T> elementType) {
        JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, elementType);
        try {
            return OBJECT_MAPPER.readValue(content, javaType);
        } catch (IOException e) {
            throw new IllegalArgumentException("反序列化 JSON 数组失败: " + content, e);
        }
    }


    /**
     * JSON 字符串转 List
     */
    public static <T> List<T> toList(String content, TypeReference<List<T>> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(content, typeReference);
        } catch (IOException e) {
            throw new IllegalArgumentException("反序列化 JSON 数组失败: " + content, e);
        }
    }
}
